package main

import "fmt"

/*
切片相当于长度可以动态扩张的数组
*/

//array[start:end]从数组身上截取下标为[start,end)片段，形成切片
//start代表开始下标，不写默认代表从头开始切
//end代表结束下标（本身不被包含），不写默认截取到末尾
func main031() {
	var array = [10]int{0, 11, 22, 33, 44, 55, 66, 77, 88, 99}

	//含头不含尾，从array的第0项截取到第9项
	slice := array[0:10]
	fmt.Printf("array的类型是%T，值是%v\n", array, array) //[10]int,[0 11 22 33 44 55 66 77 88 99]
	fmt.Printf("slice的类型是%T，值是%v\n", slice, slice) //[]int,[0 11 22 33 44 55 66 77 88 99]

	slice = array[0:5]
	fmt.Printf("slice的类型是%T，值是%v\n", slice, slice) //

	slice = array[2:5]
	fmt.Printf("slice的类型是%T，值是%v\n", slice, slice)

	slice = array[:5]
	fmt.Printf("slice的类型是%T，值是%v\n", slice, slice)

	slice = array[2:]
	fmt.Printf("slice的类型是%T，值是%v\n", slice, slice)

	slice = array[:]
	fmt.Printf("slice的类型是%T，值是%v\n", slice, slice)

	//也可以对切片进行截取，得到切片
	sonSlice := slice[:]
	fmt.Printf("sonSlice的类型是%T，值是%v\n", sonSlice, sonSlice)

}

//向切片中追加元素
//遍历切片
func main032() {

	//初始化一个没有元素的整型切片
	var slice []int = []int{}
	fmt.Printf("类型是%T\n", slice)                     //[]int
	fmt.Printf("切片的长度是%d,值是%v\n", len(slice), slice) //0,[]

	slice = append(slice, 0)
	fmt.Printf("切片的长度是%d,值是%v\n", len(slice), slice) //1,[0]

	slice = append(slice, 11, 22, 33)
	fmt.Printf("切片的长度是%d,值是%v\n", len(slice), slice) //4,[0 11 22 33]

	for i := 0; i < len(slice); i++ {
		fmt.Printf("slice的第%v个元素的值是%v\n", i, slice[i])
	}

	for index, value := range slice {
		fmt.Printf("slice的第%d个元素是%d\n", index, value)
	}

}

//cap(slice)获得切片的容量
//创建之初，容量等于长度
//扩张时，一旦容量无法满足需要，就以翻倍的策略扩容
func main033() {
	var slice = []int{1, 2, 3} //len=3,cap=3
	slice = append(slice, 4)   //len=4,cap=6
	fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))

	//slice = append(slice, 1)
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))
	//
	//slice = append(slice, 2)
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))
	//
	//slice = append(slice, 3)
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))
	//
	//slice = append(slice, 4)
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))
	//slice = append(slice, 5)
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))
	//slice = append(slice, 6)
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))
	//slice = append(slice, 7)
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))
	//slice = append(slice, 8)
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))
	//slice = append(slice, 9)
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))
	//slice = append(slice, 10)
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))
	//slice = append(slice, 11, 12, 13, 14, 15, 16)
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))
	//slice = append(slice, 17)
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))
	//
	//for i := 18; i < 33; i++ {
	//	slice = append(slice, i)
	//}
	//
	//fmt.Printf("slice的长度是%d，容量是%d\n", len(slice), cap(slice))

}

/*兼并另一个切片*/
func main0331() {
	var slice1 = []int{1, 2, 3} //len=3,cap=3
	slice2 := []int{5, 6, 7, 8}

	//slice1兼并slice2
	//for _, value := range slice2 {
	//	slice1 = append(slice1, value)
	//}
	slice1 = append(slice1, slice2...)
	fmt.Println(slice1)
}

/*创建指定长度和容量的切片*/
func main034() {
	slice := []int{1, 2, 3}
	fmt.Println(slice)//[1 2 3]
	fmt.Println(len(slice), cap(slice))//3 3

	////创建长度为3的整型切片
	//slice := make([]int, 3)
	////创建长度为3、容量为5的整型切片
	////slice := make([]int, 3, 5)
	//fmt.Println(slice)
	//fmt.Println(len(slice), cap(slice))
}


//扩容策略：容量不够时，容量*2(有时+2)，找到一片新的连续内存，将原有元素拷贝过去
func main035() {

	//创建一个0长度（容量默认和长度一样）的整型切片
	slice1 := make([]int, 0)
	fmt.Println(slice1, len(slice1), cap(slice1))//[],0,0

	slice1 = append(slice1, 1)
	fmt.Println("len=",len(slice1),"cap=",cap(slice1),"s=",slice1,"首元素地址 =",&slice1[0])//1,1,[1]
	slice1 = append(slice1, 2)
	fmt.Println("len=",len(slice1),"cap=",cap(slice1),"s=",slice1,"首元素地址 =",&slice1[0])//2,2,[1 2]，地址变化
	slice1 = append(slice1, 3)
	fmt.Println("len=",len(slice1),"cap=",cap(slice1),"s=",slice1,"首元素地址 =",&slice1[0])//3,4,[1 2 3]，地址变化
	slice1 = append(slice1, 4)
	fmt.Println("len=",len(slice1),"cap=",cap(slice1),"s=",slice1,"首元素地址 =",&slice1[0])//4,4,[1 2 3 4]
	slice1 = append(slice1, 5)
	fmt.Println("len=",len(slice1),"cap=",cap(slice1),"s=",slice1,"首元素地址 =",&slice1[0])//5,8,[1 2 3 4 5]，地址变化
	slice1 = append(slice1, 6,7)
	fmt.Println("len=",len(slice1),"cap=",cap(slice1),"s=",slice1,"首元素地址 =",&slice1[0])//7,8,[1 2 3 4 5 6 7]
	slice1 = append(slice1, 8,9,10)
	fmt.Println("len=",len(slice1),"cap=",cap(slice1),"s=",slice1,"首元素地址 =",&slice1[0])//10,16,[1 2 3 4 5 6 7 8 9 10]，地址变化
}

//切片扩容的一刹那，所有元素的地址都重新拷贝到了一片新的连续内存中
func main() {
	var array = [5]int{0, 1, 2, 3, 4}

	//切片不是拷贝，而是地址引用
	slice1 := array[:]
	slice2 := slice1[:]//len=5,cap=5

	//array，slice1，slice2的具有完全相同的元素初始地址
	fmt.Printf("%p,%p,%p\n", &array, &slice1, &slice2)//各不相同（栈内存）
	fmt.Printf("%p,%p,%p\n", &array[0], &slice1[0], &slice2[0])//相同
	fmt.Printf("%p,%p,%p\n", &array[1], &slice1[1], &slice2[1])//相同

	//牵一发而动全身
	array[1] = 11
	slice1[2] = 222
	slice2[3] = 3333
	fmt.Println(array)  //[0,11,222,3333,4]
	fmt.Println(slice1) //[0,11,222,3333,4]
	fmt.Println(slice2) //[0,11,222,3333,4]

	//slice2扩容之后，所有元素的地址都发生了迁移(拷贝了一份)
	slice2 = append(slice2, 5,6,7)
	array[0] = 10
	slice1[1] = 111
	slice2[0] = 1000
	fmt.Println(array)  //[10,111,222,3333,4]
	fmt.Println(slice1) //[10,111,222,3333,4]
	fmt.Println(slice2) //[1000,11,222,3333,4]

	fmt.Printf("addr2=%p,cap2=%d\n",&slice2,cap(slice2))

}
